<!--
 * @Author: Xujianchen
 * @Date: 2024-07-29 16:09:15
 * @LastEditors: xujianchen
 * @LastEditTime: 2024-07-29 16:16:27
 * @Description: 
-->
<template>
  <div class="count-to-wrapper">
    <slot name="left" />
    <p class="content-outer">
      <span
        :id="counterId"
        ref="countupRef"
        :class="['count-to-count-text', 'ordinary', countClass]"
      ></span>
      <i :class="['count-to-unit-text', unitClass]">{{ unitText }}</i>
    </p>
    <slot name="right" />
  </div>
</template>

<script setup>
import { CountUp } from 'countup.js'

const props = defineProps({
  init: {
    type: Number,
    default: 0,
  },
  /**
   * @description 起始值，即动画开始前显示的数值
   */
  startVal: {
    type: Number,
    default: 1110,
  },
  /**
   * @description 结束值，即动画结束后显示的数值
   */
  end: {
    type: Number,
    required: true,
  },
  /**
   * @description 保留几位小数
   */
  decimals: {
    type: Number,
    default: 0,
  },
  /**
   * @description 分隔整数和小数的符号，默认是小数点
   */
  decimal: {
    type: String,
    default: '.',
  },
  /**
   * @description 动画持续的时间，单位是秒
   */
  duration: {
    type: Number,
    default: 2,
  },
  /**
   * @description 动画延迟开始的时间，单位是秒
   */
  delay: {
    type: Number,
    default: 0,
  },
  /**
   * @description 是否禁用easing动画效果
   */
  uneasing: {
    type: Boolean,
    default: false,
  },
  /**
   * @description 是否使用分组，分组后每三位会用一个符号分隔
   */
  useGroup: {
    type: Boolean,
    default: false,
  },
  /**
   * @description 用于分组(useGroup)的符号
   */
  separator: {
    type: String,
    default: ',',
  },
  /**
   * @description 是否简化显示，设为true后会使用unit单位来做相关省略
   */
  simplify: {
    type: Boolean,
    default: false,
  },
  /**
   * @description 自定义单位，如[3, 'K+'], [6, 'M+']即大于3位数小于6位数的用k+来做省略
   *              1000即显示为1K+
   */
  unit: {
    type: Array,
    default() {
      return [
        [3, 'K+'],
        [6, 'M+'],
        [9, 'B+'],
      ]
    },
  },
  countClass: {
    type: String,
    default: '',
  },
  unitClass: {
    type: String,
    default: '',
  },
})

const countupRef = ref(null)
const counter = ref(null)
const unitText = ref('')

const counterId = computed(() => `count_to_${getCurrentInstance().uid}`)

onMounted(async () => {
  await nextTick()
  const p = props
  const endVal = getValue(p.end)
  counter.value = new CountUp(countupRef.value, p.end, endVal, p.decimals, p.duration, {
    useEasing: !p.uneasing,
    useGrouping: p.useGroup,
    separator: p.separator,
    decimal: p.decimal,
  })
  setTimeout(() => {
    if (!counter.value.error) counter.value.start()
  }, p.delay)
})

watch(
  () => props.end,
  (newVal) => {
    const endVal = getValue(newVal)
    counter.value.update(endVal)
  },
)

function getHandleVal(val, len) {
  const p = props
  return {
    endVal: parseInt(val / Math.pow(10, p.unit[len - 1][0]), 10),
    unitText: p.unit[len - 1][1],
  }
}

function transformValue(val) {
  const p = props
  const len = p.unit.length
  let res = {
    endVal: 0,
    unitText: '',
  }
  if (val < Math.pow(10, this.unit[0][0])) res.endVal = val
  else {
    for (let i = 1; i < len; i++) {
      if (val >= Math.pow(10, p.unit[i - 1][0]) && val < Math.pow(10, p.unit[i][0])) res = getHandleVal(val, i)
    }
  }
  if (val > Math.pow(10, p.unit[len - 1][0])) res = getHandleVal(val, len)
  return res
}

function getValue(val) {
  const p = props
  let res = 0
  if (p.simplify) {
    const { endVal, unitText: unitData } = transformValue(val)
    unitText.value = unitData
    res = endVal
  } else {
    res = val
  }
  return res
}
</script>

<style scoped lang='scss'>
.count-to-wrapper {
  .content-outer {
    display: inline-block;

    .ordinary {
      font-size: $font-size-medium-x;
      color: var(--el-text-color);
    }

    .count-to-unit-text {
      font-style: normal;
    }
  }
}
</style>